package me.zhengjie.modules.system.rest

import cn.hutool.core.lang.Dict
import me.zhengjie.common.exception.BadRequestException
import me.zhengjie.common.utils.*
import me.zhengjie.logging.annotation.Log
import me.zhengjie.modules.system.domain.*
import me.zhengjie.modules.system.service.RoleService
import me.zhengjie.modules.system.service.dto.RoleDTO
import me.zhengjie.modules.system.service.dto.RoleQueryCriteria
import me.zhengjie.modules.system.service.dto.RoleSmallDTO

import io.swagger.v3.oas.annotations.media.Schema
import jakarta.servlet.http.HttpServletResponse
import org.springframework.data.domain.Pageable
import org.springframework.data.domain.Sort
import org.springframework.data.web.PageableDefault
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import java.io.IOException
import java.util.*
import java.util.stream.Collectors

/**
 * @author Kuki Wu
 * @date 2018-12-03
 */
@Schema(description = "系统：角色管理")
@RestController
@RequestMapping("/api/roles")
class RoleController(private val roleService: RoleService) {
    @Schema(description = "获取单个role")
    @GetMapping(value = ["/{id}"])
    @PreAuthorize("@el.check('roles:list')")
    fun getRoles(@PathVariable id: Long?): ResponseEntity<*> {
        return ResponseEntity(roleService.findById(id!!), HttpStatus.OK)
    }

    @Log("导出角色数据")
    @Schema(description = "导出角色数据")
    @GetMapping(value = ["/download"])
    @PreAuthorize("@el.check('role:list')")
    @Throws(
        IOException::class
    )
    fun download(response: HttpServletResponse?, criteria: RoleQueryCriteria?) {
        roleService.download(roleService.queryAll(criteria!!) as MutableList<RoleDTO>, response)
    }

    @Schema(description = "返回全部的角色")
    @GetMapping(value = ["/all"])
    @PreAuthorize("@el.check('roles:list','user:add','user:edit')")
    fun getAll(
        @PageableDefault(
            value = 2000,
            sort = ["level"],
            direction = Sort.Direction.ASC
        ) pageable: Pageable?
    ): ResponseEntity<*> {
        return ResponseEntity(roleService.queryAll(pageable), HttpStatus.OK)
    }

    @Log("查询角色")
    @Schema(description = "查询角色")
    @GetMapping
    @PreAuthorize("@el.check('roles:list')")
    fun getRoles(criteria: RoleQueryCriteria?, pageable: Pageable?): ResponseEntity<*> {
        return ResponseEntity(roleService.queryAll(criteria!!, pageable), HttpStatus.OK)
    }

    @get:GetMapping(value = ["/level"])
    @get:Schema(description = "获取用户级别")
    val level: ResponseEntity<*>
        get() {
            val levels =
                roleService.findByUsersId(SecurityUtils.userId)!!.stream().map { obj: RoleSmallDTO? -> obj!!.level }
                    .collect(Collectors.toList())
            return ResponseEntity(Dict.create().set("level", Collections.min(levels as Collection<Int>)), HttpStatus.OK)
        }

    @Log("新增角色")
    @Schema(description = "新增角色")
    @PostMapping
    @PreAuthorize("@el.check('roles:add')")
    fun create(@Validated @RequestBody resources: Role): ResponseEntity<*> {
        if (resources.id != null) {
            throw BadRequestException("A new " + ENTITY_NAME + " cannot already have an ID")
        }
        return ResponseEntity(roleService.create(resources), HttpStatus.CREATED)
    }

    @Log("修改角色")
    @Schema(description = "修改角色")
    @PutMapping
    @PreAuthorize("@el.check('roles:edit')")
    fun update(
        @Validated(
            Role.Update::class
        ) @RequestBody resources: Role?
    ): ResponseEntity<*> {
        roleService.update(resources!!)
        return ResponseEntity<Any?>(HttpStatus.NO_CONTENT)
    }

    @Log("修改角色菜单")
    @Schema(description = "修改角色菜单")
    @PutMapping(value = ["/menu"])
    @PreAuthorize("@el.check('roles:edit')")
    fun updateMenu(@RequestBody resources: Role): ResponseEntity<*> {
        roleService.updateMenu(resources, roleService.findById(resources.id!!))
        return ResponseEntity<Any?>(HttpStatus.NO_CONTENT)
    }

    @Log("删除角色")
    @Schema(description = "删除角色")
    @DeleteMapping(value = ["/{id}"])
    @PreAuthorize("@el.check('roles:del')")
    fun delete(@PathVariable id: Long?): ResponseEntity<*> {
        try {
            roleService.delete(id!!)
        } catch (e: Throwable) {
            ThrowableUtil.throwForeignKeyException(e, "该角色存在用户关联，请取消关联后再试")
        }
        return ResponseEntity<Any?>(HttpStatus.OK)
    }

    companion object {
        private const val ENTITY_NAME = "role"
    }
}